#!/usr/bin/perl

print "Starting Module Parsing\n";

$mod_short_name = $ARGV[0];
$mod_start_0 = $ARGV[1];
$mod_start_1 = $ARGV[2];
$mod_start_2 = $ARGV[3];
$mod_start_3 = $ARGV[4];
$use_core_0 = $ARGV[5];
$use_core_1 = $ARGV[6];
$use_core_2 = $ARGV[7];
$use_core_3 = $ARGV[8];

print "Starting Disassembly...";
`xobjdump -s ../bin/XC-1A/os_flasher.xe`;
$num_cores = 4;
`xobjdump -d -o output0 image_n0c0.elf`;
`xobjdump -d -o output1 image_n0c1.elf`;
`xobjdump -d -o output2 image_n0c2.elf`;
`xobjdump -d -o output3 image_n0c3.elf`;
print "Done\n";

`del ../src/perl_out.h`;

print "Filling Header..\n";

open(OUT, ">>../src/perl_out.h");
print OUT "#define MOD_NAME \"",$mod_short_name,"\"\n";

open(OBJ, "output0") or 
  die("Error: cannot open file output\n");

$core = 0;
$mod_start = $mod_start_0;

@lines = <OBJ>;
@names = (0);
$names_cnt = 0;
%start = (0);
%end = (0);
@dep = {0};
%dep_start = {};
%dep_end = {};
$dep_count = 0;
$double = 0;
$max_dp = 0;
$max_cp = 0;
%cp_start = {};
%cp_end = {};
@cp_calls = {};
$cp_counts = 0;
%dp_start = {};
%dp_end = {};
@dp_calls = {};
$dp_counts = 0;
$start_cp = 1;
$start_dp = 1;
for($count = 0; $count < $#lines; $count++) {
	if ($lines[$count++] =~ /\<(.+)\>\:/) {
		if ($double == 0) {
			$name = $1;
			$names[$names_cnt] = $1;
			#print $names[$names_cnt],"\n";
		}
		if ($lines[$count] =~ /(0x[0-9a-f]+)/) {
			#print "Calls:\n";
			$count++;
			$start{$name} = hex($1);
			$end{$name} = hex($1);
			#print $start[$names_cnt],"\n";
			$dep_start{$name} = $dep_count;
			$dp_start{$name} = $dp_count;
			$cp_start{$name} = $cp_count;
			while ($lines[$count] =~ /(0x[0-9a-f]+)/) {
				$end{$name} = hex($1);
				if ($lines[$count] =~ /cp\[(0x[0-9a-f]+)\]/) {
					$cp_calls[$cp_count++] = hex($1);
					##print "\t",$cp_calls[$cp_count++],"\n";
				}
				if ($lines[$count] =~ /dp\[(0x[0-9a-f]+)\]/) {
					$dp_calls[$dp_count++] = hex($1);
					##print "\t",$dp_calls[$dp_count++],"\n";
				}
				if ($lines[$count] =~ /set.*cp/) {
					if ($lines[$count-1] =~ /r[0-9]+, (0x[0-9a-f]+)/) {
						if ($start_cp == 1) {
							##print "CP: ",$1;
							$cp = 2*hex($1) + $end{$name};
							##print "Real: ",$cp,"\n";
							$start_cp = 0;
						}
					}
				}
				if ($lines[$count] =~ /set.*dp/) {
					if ($lines[$count-1] =~ /r[0-9]+, (0x[0-9a-f]+)/) {
						if ($start_dp == 1) {
							##print "DP: ",$1;
							$dp = 2*hex($1) + $end{$name};
							##print "Real: ",$dp,"\n";
							$start_dp = 0;
						}
					}
				}
				if ($lines[$count] =~ /\<([_a-zA-Z0-9]+)\>/) {
					$dep[$dep_count++] = $1;
					##print "\t",$dep[$dep_count++],"\n";
				}
				$count++;
			}
			#print $start{$name}," ";
			#print $end{$name},"\n";
			$names_cnt++;
			$dep_end{$name} = $dep_count;
			$dp_end{$name} = $dp_count;
			$cp_end{$name} = $cp_count;
			#print "\n";
			$double = 0;
		} else {
			$count--;
			$double = 1;
		}

	}
}

$min = 1280000;
$max = 0;
##print "Start: ",$min," End: ",$max,"\n";
print_tree($mod_start,0);

sub print_tree {
	my $name = $_[0];
	my $ind = $_[1];
	if ($end{$name} > $max) {
		$max = $end{$name};
	}
	if ($start{$name} < $min) {
		$min = $start{$name};
	}
	print OUT "//";
	for (my $j = 0; $j < $ind; $j++) {
		print OUT "\t";
	}
	print OUT $name,"\n";
	print OUT "//";
	for (my $j = 0; $j < $ind; $j++) {	
		print OUT "\t";
	}
	print OUT $start{$name},"\n";
	for (my $i = $dp_start{$name}; $i < $dp_end{$name}; $i++) {
		if ($dp_calls[$i] > $max_dp) {
			$max_dp = $dp_calls[$i];
		}
	}
	for (my $i = $cp_start{$name}; $i < $cp_end{$name}; $i++) {
		if ($cp_calls[$i] > $max_cp) {
			$max_cp = $cp_calls[$i];
		}
	}
	for (my $i = $dep_start{$name}; $i < $dep_end{$name}; $i++) {
		print_tree($dep[$i],$ind+1);
	}
}
if ($max_cp*2 + $cp > $max) {
	$max = $cp + 2*$max_cp;
}
if ($max_dp*2 + $dp > $max) {
	$max = $dp + 2*$max_dp;
}
if ($use_core_0) {
	print OUT "#define MOD_FUNC_",$core," ",$mod_start,"\n";
	print OUT "#define MOD_OFFSET_",$core," ",$start{$mod_start},"\n";
	print OUT "#define MOD_START_",$core," ",$min,"\n";
print OUT "#define MOD_SIZE_",$core," ",($max - $min),"\n";
} else {
	print OUT "#define MOD_OFFSET_",$core," 0","\n";
	print OUT "#define MOD_START_",$core," 0","\n";
print OUT "#define MOD_SIZE_",$core," ",(0),"\n";
}
print OUT "#define MOD_CP_",$core," ",$cp,"\n";
print OUT "#define MOD_DP_",$core," ",$dp,"\n";
print OUT "#define MOD_STACK_",$core," ",(0x500),"\n";

print "Core 0 Parsing Complete\n";

open(OBJ, "output1") or 
  die("Error: cannot open file output\n");

$core = 1;
$mod_start = $mod_start_1;

@lines = [];
@lines = <OBJ>;
@names = (0);
$names_cnt = 0;
%start = (0);
%end = (0);
@dep = {0};
%dep_start = {};
%dep_end = {};
$dep_count = 0;
$double = 0;
$max_dp = 0;
$max_cp = 0;
%cp_start = {};
%cp_end = {};
@cp_calls = {};
$cp_counts = 0;
%dp_start = {};
%dp_end = {};
@dp_calls = {};
$dp_counts = 0;
$start_cp = 1;
$start_dp = 1;
for($count = 0; $count < $#lines; $count++) {
	if ($lines[$count++] =~ /\<(.+)\>\:/) {
		if ($double == 0) {
			$name = $1;
			$names[$names_cnt] = $1;
			#print $names[$names_cnt],"\n";
		}
		if ($lines[$count] =~ /(0x[0-9a-f]+)/) {
			##print "Calls:\n";
			$count++;
			$start{$name} = hex($1);
			$end{$name} = hex($1);
			#print $start[$names_cnt],"\n";
			$dep_start{$name} = $dep_count;
			$dp_start{$name} = $dp_count;
			$cp_start{$name} = $cp_count;
			while ($lines[$count] =~ /(0x[0-9a-f]+)/) {
				$end{$name} = hex($1);
				if ($lines[$count] =~ /cp\[(0x[0-9a-f]+)\]/) {
					$cp_calls[$cp_count++] = hex($1);
					#print "\t",$cp_calls[$cp_count++],"\n";
				}
				if ($lines[$count] =~ /dp\[(0x[0-9a-f]+)\]/) {
					$dp_calls[$dp_count++] = hex($1);
					#print "\t",$dp_calls[$dp_count++],"\n";
				}
				if ($lines[$count] =~ /set.*cp/) {
					if ($lines[$count-1] =~ /r[0-9]+, (0x[0-9a-f]+)/) {
						if ($start_cp == 1) {
							#print "CP: ",$1;
							$cp = 2*hex($1) + $end{$name};
							#print "Real: ",$cp,"\n";
							$start_cp = 0;
						}
					}
				}
				if ($lines[$count] =~ /set.*dp/) {
					if ($lines[$count-1] =~ /r[0-9]+, (0x[0-9a-f]+)/) {
						if ($start_dp == 1) {
							#print "DP: ",$1;
							$dp = 2*hex($1) + $end{$name};
							#print "Real: ",$dp,"\n";
							$start_dp = 0;
						}
					}
				}
				if ($lines[$count] =~ /\<([_a-zA-Z0-9]+)\>/) {
					$dep[$dep_count++] = $1;
					#print "\t",$dep[$dep_count++],"\n";
				}
				$count++;
			}
			#print $start{$name}," ";
			#print $end{$name},"\n";
			$names_cnt++;
			$dep_end{$name} = $dep_count;
			$dp_end{$name} = $dp_count;
			$cp_end{$name} = $cp_count;
			#print "\n";
			$double = 0;
		} else {
			$count--;
			$double = 1;
		}

	}
}

$min = 1280000;
$max = 0;
#print "Start: ",$min," End: ",$max,"\n";
print_tree($mod_start,0);

#sub print_tree {
#	my $name = $_[0];
#	my $ind = $_[1];
#	if ($end{$name} > $max) {
#		$max = $end{$name};
#	}
#	if ($start{$name} < $min) {
#		$min = $start{$name};
#	}
#	for (my $j = 0; $j < $ind; $j++) {
#		#print "\t";
#	}
#	print $name,"\n";
#	for (my $i = $dp_start{$name}; $i < $dp_end{$name}; $i++) {
#		if ($dp_calls[$i] > $max_dp) {
#			$max_dp = $dp_calls[$i];
#		}
#	}
#	for (my $i = $cp_start{$name}; $i < $cp_end{$name}; $i++) {
#		if ($cp_calls[$i] > $max_cp) {
#			$max_cp = $cp_calls[$i];
#		}
#	}
#	for (my $i = $dep_start{$name}; $i < $dep_end{$name}; $i++) {
#		print_tree($dep[$i],$ind+1);
#	}
#}
if ($max_cp*2 + $cp > $max) {
	$max = $cp + 2*$max_cp;
}
if ($max_dp*2 + $dp > $max) {
	$max = $dp + 2*$max_dp;
}
if ($use_core_1) {
	print OUT "#define MOD_FUNC_",$core," ",$mod_start,"\n";
print OUT "#define MOD_START_",$core," ",$min,"\n";
print OUT "#define MOD_OFFSET_",$core," ",$start{$mod_start},"\n";
print OUT "#define MOD_SIZE_",$core," ",($max - $min),"\n";
} else {
	print OUT "#define MOD_OFFSET_",$core," 0","\n";
	print OUT "#define MOD_START_",$core," 0","\n";
print OUT "#define MOD_SIZE_",$core," ",(0),"\n";
}
print OUT "#define MOD_CP_",$core," ",$cp,"\n";
print OUT "#define MOD_DP_",$core," ",$dp,"\n";
print OUT "#define MOD_STACK_",$core," ",(0x500),"\n";

print "Core 1 Parsing Complete\n";

open(OBJ, "output2") or 
  die("Error: cannot open file output\n");

$core = 2;
$mod_start = $mod_start_2;

@lines = [];
@lines = <OBJ>;
@names = (0);
$names_cnt = 0;
%start = (0);
%end = (0);
@dep = {0};
%dep_start = {};
%dep_end = {};
$dep_count = 0;
$double = 0;
$max_dp = 0;
$max_cp = 0;
%cp_start = {};
%cp_end = {};
@cp_calls = {};
$cp_counts = 0;
%dp_start = {};
%dp_end = {};
@dp_calls = {};
$dp_counts = 0;
$start_cp = 1;
$start_dp = 1;
for($count = 0; $count < $#lines; $count++) {
	if ($lines[$count++] =~ /\<(.+)\>\:/) {
		if ($double == 0) {
			$name = $1;
			$names[$names_cnt] = $1;
			#print $names[$names_cnt],"\n";
		}
		if ($lines[$count] =~ /(0x[0-9a-f]+)/) {
			#print "Calls:\n";
			$count++;
			$start{$name} = hex($1);
			$end{$name} = hex($1);
			#print $start[$names_cnt],"\n";
			$dep_start{$name} = $dep_count;
			$dp_start{$name} = $dp_count;
			$cp_start{$name} = $cp_count;
			while ($lines[$count] =~ /(0x[0-9a-f]+)/) {
				$end{$name} = hex($1);
				if ($lines[$count] =~ /cp\[(0x[0-9a-f]+)\]/) {
					$cp_calls[$cp_count++] = hex($1);
					#print "\t",$cp_calls[$cp_count++],"\n";
				}
				if ($lines[$count] =~ /dp\[(0x[0-9a-f]+)\]/) {
					$dp_calls[$dp_count++] = hex($1);
					#print "\t",$dp_calls[$dp_count++],"\n";
				}
				if ($lines[$count] =~ /set.*cp/) {
					if ($lines[$count-1] =~ /r[0-9]+, (0x[0-9a-f]+)/) {
						if ($start_cp == 1) {
							#print "CP: ",$1;
							$cp = 2*hex($1) + $end{$name};
							#print "Real: ",$cp,"\n";
							$start_cp = 0;
						}
					}
				}
				if ($lines[$count] =~ /set.*dp/) {
					if ($lines[$count-1] =~ /r[0-9]+, (0x[0-9a-f]+)/) {
						if ($start_dp == 1) {
							#print "DP: ",$1;
							$dp = 2*hex($1) + $end{$name};
							#print "Real: ",$dp,"\n";
							$start_dp = 0;
						}
					}
				}
				if ($lines[$count] =~ /\<([_a-zA-Z0-9]+)\>/) {
					$dep[$dep_count++] = $1;
					#print "\t",$dep[$dep_count++],"\n";
				}
				$count++;
			}
			#print $start{$name}," ";
			#print $end{$name},"\n";
			$names_cnt++;
			$dep_end{$name} = $dep_count;
			$dp_end{$name} = $dp_count;
			$cp_end{$name} = $cp_count;
			#print "\n";
			$double = 0;
		} else {
			$count--;
			$double = 1;
		}

	}
}

$min = 1280000;
$max = 0;
#print "Start: ",$min," End: ",$max,"\n";
print_tree($mod_start,0);

#sub print_tree {
#	my $name = $_[0];
#	my $ind = $_[1];
#	if ($end{$name} > $max) {
#		$max = $end{$name};
#	}
#	if ($start{$name} < $min) {
#		$min = $start{$name};
#	}
#	for (my $j = 0; $j < $ind; $j++) {
#		#print "\t";
#	}
#	#print $name,"\n";
#	for (my $i = $dp_start{$name}; $i < $dp_end{$name}; $i++) {
#		if ($dp_calls[$i] > $max_dp) {
#			$max_dp = $dp_calls[$i];
#		}
#	}
#	for (my $i = $cp_start{$name}; $i < $cp_end{$name}; $i++) {
#		if ($cp_calls[$i] > $max_cp) {
#			$max_cp = $cp_calls[$i];
#		}
#	}
#	for (my $i = $dep_start{$name}; $i < $dep_end{$name}; $i++) {
#		print_tree($dep[$i],$ind+1);
#	}
#}
if ($max_cp*2 + $cp > $max) {
	$max = $cp + 2*$max_cp;
}
if ($max_dp*2 + $dp > $max) {
	$max = $dp + 2*$max_dp;
}
if ($use_core_2) {
	print OUT "#define MOD_FUNC_",$core," ",$mod_start,"\n";
print OUT "#define MOD_START_",$core," ",$min,"\n";
print OUT "#define MOD_OFFSET_",$core," ",$start{$mod_start},"\n";
print OUT "#define MOD_SIZE_",$core," ",($max - $min),"\n";
} else {
	print OUT "#define MOD_OFFSET_",$core," 0","\n";
	print OUT "#define MOD_START_",$core," 0","\n";
print OUT "#define MOD_SIZE_",$core," ",(0),"\n";
}
print OUT "#define MOD_CP_",$core," ",$cp,"\n";
print OUT "#define MOD_DP_",$core," ",$dp,"\n";
print OUT "#define MOD_STACK_",$core," ",(0x500),"\n";

print "Core 2 Parsing Complete\n";

open(OBJ, "output3") or 
  die("Error: cannot open file output\n");

$core = 3;
$mod_start = $mod_start_3;

@lines = [];
@lines = <OBJ>;
@names = (0);
$names_cnt = 0;
%start = (0);
%end = (0);
@dep = {0};
%dep_start = {};
%dep_end = {};
$dep_count = 0;
$double = 0;
$max_dp = 0;
$max_cp = 0;
%cp_start = {};
%cp_end = {};
@cp_calls = {};
$cp_counts = 0;
%dp_start = {};
%dp_end = {};
@dp_calls = {};
$dp_counts = 0;
$start_cp = 1;
$start_dp = 1;
for($count = 0; $count < $#lines; $count++) {
	if ($lines[$count++] =~ /\<(.+)\>\:/) {
		if ($double == 0) {
			$name = $1;
			$names[$names_cnt] = $1;
			#print $names[$names_cnt],"\n";
		}
		if ($lines[$count] =~ /(0x[0-9a-f]+)/) {
			#print "Calls:\n";
			$count++;
			$start{$name} = hex($1);
			$end{$name} = hex($1);
			#print $start[$names_cnt],"\n";
			$dep_start{$name} = $dep_count;
			$dp_start{$name} = $dp_count;
			$cp_start{$name} = $cp_count;
			while ($lines[$count] =~ /(0x[0-9a-f]+)/) {
				$end{$name} = hex($1);
				if ($lines[$count] =~ /cp\[(0x[0-9a-f]+)\]/) {
					$cp_calls[$cp_count++] = hex($1);
					#print "\t",$cp_calls[$cp_count++],"\n";
				}
				if ($lines[$count] =~ /dp\[(0x[0-9a-f]+)\]/) {
					$dp_calls[$dp_count++] = hex($1);
					#print "\t",$dp_calls[$dp_count++],"\n";
				}
				if ($lines[$count] =~ /set.*cp/) {
					if ($lines[$count-1] =~ /r[0-9]+, (0x[0-9a-f]+)/) {
						if ($start_cp == 1) {
							#print "CP: ",$1;
							$cp = 2*hex($1) + $end{$name};
							#print "Real: ",$cp,"\n";
							$start_cp = 0;
						}
					}
				}
				if ($lines[$count] =~ /set.*dp/) {
					if ($lines[$count-1] =~ /r[0-9]+, (0x[0-9a-f]+)/) {
						if ($start_dp == 1) {
							#print "DP: ",$1;
							$dp = 2*hex($1) + $end{$name};
							#print "Real: ",$dp,"\n";
							$start_dp = 0;
						}
					}
				}
				if ($lines[$count] =~ /\<([_a-zA-Z0-9]+)\>/) {
					$dep[$dep_count++] = $1;
					#print "\t",$dep[$dep_count++],"\n";
				}
				$count++;
			}
			#print $start{$name}," ";
			#print $end{$name},"\n";
			$names_cnt++;
			$dep_end{$name} = $dep_count;
			$dp_end{$name} = $dp_count;
			$cp_end{$name} = $cp_count;
			#print "\n";
			$double = 0;
		} else {
			$count--;
			$double = 1;
		}

	}
}

$min = 1280000;
$max = 0;
#print "Start: ",$min," End: ",$max,"\n";
print_tree($mod_start,0);

#sub print_tree {
#	my $name = $_[0];
#	my $ind = $_[1];
#	if ($end{$name} > $max) {
#		$max = $end{$name};
#	}
#	if ($start{$name} < $min) {
#		$min = $start{$name};
#	}
#	for (my $j = 0; $j < $ind; $j++) {
#		#print "\t";
#	}
#	#print $name,"\n";
#	for (my $i = $dp_start{$name}; $i < $dp_end{$name}; $i++) {
#		if ($dp_calls[$i] > $max_dp) {
#			$max_dp = $dp_calls[$i];
#		}
#	}
#	for (my $i = $cp_start{$name}; $i < $cp_end{$name}; $i++) {
#		if ($cp_calls[$i] > $max_cp) {
#			$max_cp = $cp_calls[$i];
#		}
#	}
#	for (my $i = $dep_start{$name}; $i < $dep_end{$name}; $i++) {
#		print_tree($dep[$i],$ind+1);
#	}
#}
if ($max_cp*2 + $cp > $max) {
	$max = $cp + 2*$max_cp;
}
if ($max_dp*2 + $dp > $max) {
	$max = $dp + 2*$max_dp;
}
if ($use_core_3) {
	print OUT "#define MOD_FUNC_",$core," ",$mod_start,"\n";
print OUT "#define MOD_START_",$core," ",$min,"\n";
print OUT "#define MOD_OFFSET_",$core," ",$start{$mod_start},"\n";
print OUT "#define MOD_SIZE_",$core," ",($max - $min),"\n";
} else {
print OUT "#define MOD_SIZE_",$core," ",(0),"\n";
	print OUT "#define MOD_OFFSET_",$core," 0","\n";
	print OUT "#define MOD_START_",$core," 0","\n";
}
print OUT "#define MOD_CP_",$core," ",$cp,"\n";
print OUT "#define MOD_DP_",$core," ",$dp,"\n";
print OUT "#define MOD_STACK_",$core," ",(0x500),"\n";

print "Core 3 Parsing Complete\n";

print "Done\n";